#include "common.h"

void release(DP* ptr) 
{
	for(u16 i = 0, l = ntohs(ptr->head.qdcount); i < l; i ++)
	{
		free(ptr->qd[i].qname);
	}
	for(u16 i = 0, l = ntohs(ptr->head.ancount); i < l; i ++)
	{
		free(ptr->an[i].domain);
		free(ptr->an[i].rdata);
	}
	for(u16 i = 0, l = ntohs(ptr->head.nscount); i < l; i ++)
	{
		free(ptr->ns[i].domain);
		free(ptr->ns[i].rdata);
	}
	for(u16 i = 0, l = ntohs(ptr->head.arcount); i < l; i ++)
	{
		free(ptr->ar[i].domain);
		free(ptr->ar[i].rdata);
	}
	free(ptr->ar);
	free(ptr->an);
	free(ptr->ns);
	free(ptr->qd);
	free(ptr);
}

int tag(char v)
{
	if (v >= '0' && v <= '9')//0-9编号为0,1,...,9 
		return v - '0';
	else if (v >= 'a' && v <= 'z')//'a'-'z'编号为11,12,...,36 
		return v - 'a' + 11;
	else if (v >= 'A' && v <= 'Z')//'A'-'Z'编号为11,12,...,36
		return v - 'A' + 11;
	switch(v)
	{
		case '.': return 10;
		case '-': return 37;
		case '!': return 38;
		case '"': return 39;
		case '#': return 40;
		case '$': return 41;
		case '%': return 42;
		case '&': return 43;
		case '(': return 44;
		case ')': return 45;
		case '*': return 46;
		case '+': return 47;
		case ',': return 48;
		case '/': return 50;
		case ':': return 51;
		case ';': return 52;
		case '<': return 53;
		case '=': return 54;
		case '>': return 55;
		case '?': return 56;
		case '@': return 57;
		case '[': return 58;
		case '\\': return 59;
		case ']': return 60;
		case '^': return 61;
		case '_': return 62;
		case '`': return 63;
		case '{': return 64;
		case '|': return 65;
		case '}': return 66;
		case '~': return 67;
		case '\'': return 68;
	}
}
//! " # $ % & ' ( ) * + , - / : ; < = > ? @ [ \ ] ^ _ ` { | } ~ .

void in_wait_queue(char* domain)
{
	wait_queue_tail == (++wait_queue_tail) % wait_queue_size;
	strcpy(wait_queue[wait_queue_tail], domain);
}

void node_insert(char* domain, char* ip_2_insert, Trie** root_ptr)
{
	int len = strlen(domain);
	Trie* p = *root_ptr, * q;
	if (p == NULL) //若root为空则建立新节点
	{
		*root_ptr = (Trie*)malloc(sizeof(Trie));
		p = *root_ptr;
		if (p == NULL)
			printf("ERROR,ROOT is NULL\n");
		else
		{
			for (int j = 0; j < MAXN; j++)
				p->next[j] = NULL;
			p->ip[0] = '\0';
			p->count = 0;
		}
	}
	for (int i = 0; i < len; i++)
	{
		int id = tag(domain[i]);
		p->count++;
		if (p->next[id] == NULL)
		{
			q = (Trie*)malloc(sizeof(Trie));
			if (q == NULL)
			{
				printf("ERROR,node is NULL\n");
				exit(0);
			}
			else
			{
				for (int j = 0; j < MAXN; j++)
					q->next[j] = NULL;
				q->ip[0] = '\0';
				q->count = 0;
				p->next[id] = q;
				p = p->next[id];
			}
		}
		else
		{
			p = p->next[id];
		}
	}
	strcpy(p->ip, ip_2_insert);   //若为结尾，则将ip加入节点 
}

char* node_find(char* domain, Trie** root_ptr)//成功返回ip，失败返回NULL
{
	int len = strlen(domain);
	Trie* p = *root_ptr;
	if (p == NULL)
		return NULL;
	for (int i = 0; i < len; ++i)
	{
		int id = tag(domain[i]);
		p = p->next[id];
		if (p == NULL)   //若为空集，表示不存以此为前缀的串
			return NULL;
	}
	if (p->ip[0] == '\0')
		return NULL;
	return p->ip;
}

void node_delete(char* s, Trie** root_ptr)
{
	int len = strlen(s);
	int id = 0, pre_id = 0;
	Trie* p = *root_ptr, * q, * pre = *root_ptr;

	if (node_find(s, root_ptr) != NULL)//若存在
	{
		p->count--;
		for (int i = 0; i < len; i++)
		{
			id = tag(s[i]);
			q = p->next[id];
			q->count--;
			if (p->count <= 0)
			{
				pre->next[pre_id] = NULL;
				free(p);
			}
			pre_id = id;
			pre = p;
			p = q;
		}
		p->ip[0] = '\0';
		if (p->count <= 0)
		{
			pre->next[pre_id] = NULL;
			free(p);
		}
	}
}

void LRU_insert(char* domain, char* ip_2_insert)
{
	if (node_find(domain, &LRU_root) != NULL)
		return;
	if (LRU_is_flush == 1)//如果超出了缓冲区边界，则删去之前缓存
		node_delete(LRU_queue[LRU_queue_head], &LRU_root);
	node_insert(domain, ip_2_insert, &LRU_root);
	strcpy(LRU_queue[LRU_queue_head], domain);
	LRU_queue_head = (LRU_queue_head + 1) % LRU_SIZE;
	if (LRU_queue_head == 0) LRU_is_flush = 1;
}

char* domain_search() //查找成功返回ip，查找失败返回NULL
{
	wait_queue_head = (++wait_queue_head) % wait_queue_size;
	char* domain = wait_queue[wait_queue_head];
	char* p = node_find(domain, &LRU_root); //先到LRU查找，没找到再到本地查找
	if (p == NULL)
		return node_find(domain, &local_root);
	else
		return p;
}

void init(int argc, char** argv)
{
    config(argc,argv);// 获取运行参数 如果参数有错误 请exit(0)
    socketInit(); //windows下启动socket linux下被define了
    fileInit(); //读取dns表和建立输出到日志的 FILE* 请保存于全局变量
    
}